/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Description: Hmfs-tools quota
 */

#ifndef HMFS_UTILS_H
#define HMFS_UTILS_H

#include <cinttypes>

namespace OHOS {
namespace Hmfs {
/*-------------------------------- bit ending swap --------------------------------*/
template <typename T>
constexpr T SwapBits(T value, T mask, uint32_t offset)
{
    return ((value >> offset) & mask) | ((value & mask) << offset);
}

inline uint16_t ReverseBytes(uint16_t value)
{
    constexpr uint32_t OFFSET_0 = 8;
    return static_cast<uint16_t>(value << OFFSET_0) | static_cast<uint16_t>(value >> OFFSET_0);
}

inline uint32_t ReverseBytes(uint32_t value)
{
    constexpr uint32_t BYTES_MASK = 0xff00ffU;
    constexpr uint32_t OFFSET_0 = 8;
    constexpr uint32_t OFFSET_1 = 16;
    value = SwapBits(value, BYTES_MASK, OFFSET_0);
    return (value >> OFFSET_1) | (value << OFFSET_1);
}

inline uint64_t ReverseBytes(uint64_t value)
{
    constexpr uint64_t BYTES_MASK = 0xff00ff00ff00ffLU;
    constexpr uint64_t WORDS_MASK = 0xffff0000ffffLU;
    constexpr uint32_t OFFSET_0 = 8;
    constexpr uint32_t OFFSET_1 = 16;
    constexpr uint32_t OFFSET_2 = 32;
    value = SwapBits(value, BYTES_MASK, OFFSET_0);
    value = SwapBits(value, WORDS_MASK, OFFSET_1);
    return (value >> OFFSET_2) | (value << OFFSET_2);
}

template <typename T>
constexpr T ByteSwap(T x)
{
    if (sizeof(T) == sizeof(uint16_t)) {
        return ReverseBytes(static_cast<uint16_t>(x));
    }
    if (sizeof(T) == sizeof(uint32_t)) {
        return ReverseBytes(static_cast<uint32_t>(x));
    }
    return ReverseBytes(static_cast<uint64_t>(x));
}

#if __BYTE_ORDER == __BIG_ENDIAN
inline uint16_t NativeToLE16(uint16_t x)
{
    return ByteSwap(x);
}
inline uint32_t NativeToLE32(uint32_t x)
{
    return ByteSwap(x);
}
inline uint64_t NativeToLE64(uint64_t x)
{
    return ByteSwap(x);
}
inline uint16_t LE16ToNative(uint16_t x)
{
    return ByteSwap(x);
}
inline uint32_t LE32ToNative(uint32_t x)
{
    return ByteSwap(x);
}
inline uint64_t LE64ToNative(uint64_t x)
{
    return ByteSwap(x);
}
#elif __BYTE_ORDER == __LITTLE_ENDIAN
inline uint16_t NativeToLE16(uint16_t x)
{
    return x;
}
inline uint32_t NativeToLE32(uint32_t x)
{
    return x;
}
inline uint64_t NativeToLE64(uint64_t x)
{
    return x;
}
inline uint16_t LE16ToNative(uint16_t x)
{
    return x;
}
inline uint32_t LE32ToNative(uint32_t x)
{
    return x;
}
inline uint64_t LE64ToNative(uint64_t x)
{
    return x;
}
#endif

template <typename T, typename V>
inline void SetLeValue(T &member, V val)
{
    if constexpr (sizeof(T) == sizeof(uint16_t)) {
        member = NativeToLE16(val);
    } else if constexpr (sizeof(T) == sizeof(uint32_t)) {
        member = NativeToLE32(val);
    } else if constexpr (sizeof(T) == sizeof(uint64_t)) {
        member = NativeToLE64(val);
    } else {
        member = val;
    }
}

template <typename T>
inline T GetLeValue(T value)
{
    if constexpr (sizeof(T) == sizeof(uint16_t)) {
        return LE16ToNative(value);
    } else if constexpr (sizeof(T) == sizeof(uint32_t)) {
        return LE32ToNative(value);
    } else if constexpr (sizeof(T) == sizeof(uint64_t)) {
        return LE64ToNative(value);
    } else {
        return value;
    }
}

template <typename T, typename S>
inline T AlignUpCount(T value, S alignSize)
{
    if (alignSize == 0) {
        return 0;
    }
    return (value + alignSize - 1) / alignSize;
}

inline uint32_t AlignDown(uint32_t addrs, uint32_t size)
{
    if (size == 0) {
        return 0;
    }
    return (addrs / size) * size;
}

inline uint32_t AlignUp(uint32_t addrs, uint32_t size)
{
    return AlignDown((addrs + size - 1), size);
}

inline uint32_t RountUp(uint32_t x, uint32_t y)
{
    if (y == 0) {
        return 0;
    }
    return ((x + y - 1) / y);
}

inline uint64_t HmfsBytesToMb(uint64_t bytes)
{
    return bytes >> MB_SHIFT;
}
inline uint64_t HmfsBlksToMb(uint32_t blocks)
{
    return blocks >> BLOCKS_TO_MB_SHIFT;
}
inline uint32_t HmfsBytesToBlk(uint32_t bytes)
{
    return ((bytes) >> HMFS_BLKSIZE_BITS);
}

#define VERSION_STRING_LEN              (VERSION_TOTAL_LEN - VERSION_TIMESTAMP_LEN)

#define CP_CHECKSUM_OFFSET              (HMFS_BLOCK_SIZE - sizeof(uint32_t))
#define CP_BITMAP_OFFSET                (offsetof(CheckPointData, sitNatVersionBitmap))
#define CP_MIN_CHECKSUM_OFFSET          CP_BITMAP_OFFSET

#define CP_MAX_BITMAP_SIZE              (CP_CHECKSUM_OFFSET - CP_BITMAP_OFFSET)
#define CP_MAX_SIT_BITMAP_SIZE          (CP_MAX_BITMAP_SIZE - NAT_MIN_BITMAP_SIZE)

#define SUMMARY_JOURNAL_SIZE            (HMFS_BLOCK_SIZE - sizeof(SummaryFooter) - \
    (sizeof(SummaryEntry) * ENTRY_COUNT_IN_SUM))

#define NAT_JOURNAL_ENTRY_COUNT         ((SUMMARY_JOURNAL_SIZE - RESERVED_BYTES) / sizeof(NatJournalEntry))
#define NAT_JOURNAL_RESERVED_COUNT      ((SUMMARY_JOURNAL_SIZE - RESERVED_BYTES) % sizeof(NatJournalEntry))
#define SIT_JOURNAL_ENTRY_COUNT         ((SUMMARY_JOURNAL_SIZE - RESERVED_BYTES) / sizeof(SitJournalEntry))
#define SIT_JOURNAL_RESERVED_COUNT      ((SUMMARY_JOURNAL_SIZE - RESERVED_BYTES) % sizeof(SitJournalEntry))

#define EXTRA_INFO_RESERVED_SIZE        (SUMMARY_JOURNAL_SIZE - EXTRA_INFO_HEADER_SIZE - EXTRA_INFO_FOOTER_SIZE)

#define SET_SUM_TYPE(footer, type)      ((footer)->entryType = type)

#define HMFS_EXTRA_ISIZE_OFFSET         offsetof(HmfsInode, extraInodeSize)

#define DENTRY_BITMAP_SIZE              ((DENTRY_COUNT_IN_BLOCK + BITS_PER_BYTE - 1) / BITS_PER_BYTE)
#define RESERVED_SIZE (HMFS_BLOCK_SIZE - ((sizeof(DirEntry) + HMFS_SLOT_LEN) * \
    DENTRY_COUNT_IN_BLOCK + DENTRY_BITMAP_SIZE))

inline bool LinuxIsReg(uint16_t mode)
{
    return ((mode & LINUX_S_IFMT) == LINUX_S_IFREG);
}

inline uint64_t RoundDown(uint64_t x, uint64_t y)
{
    return (x & ~(y - 1));
}

#define SIT_VBLOCKS_MASK                ((1 << SIT_USER_BLOCK_COUNT_SHIFT) - 1)

#define SIT_ENTRIES_PER_BLOCK           (HMFS_BLOCK_SIZE / sizeof(SitEntry))

#define SIT_MAX_BITMAP_SIZE \
    (AlignUpCount(AlignUpCount(HMFS_MAX_SEGMENT, SIT_ENTRIES_PER_BLOCK), BLOCKS_PER_SEGMENT) * \
    BLOCKS_PER_SEGMENT / BITS_PER_BYTE)

#define MAX_CP_PAYLOAD  \
    (AlignUpCount(AlignUpCount(UINT32_MAX, NAT_ENTRY_PER_BLOCK), BLOCKS_PER_SEGMENT) * \
    DEFAULT_NAT_ENTRY_RATIO / PERCENTAGE_DIVISOR * BLOCKS_PER_SEGMENT / BITS_PER_BYTE + \
    SIT_MAX_BITMAP_SIZE - CP_MAX_BITMAP_SIZE)

#define SIT_BITMAP_SIZE                 (BLOCKS_PER_SEGMENT / BITS_PER_BYTE)
#define NAT_ENTRIES_PER_BLOCK           (HMFS_BLOCK_SIZE / sizeof(NatEntry))
#define NAT_ENTRY_PER_BLOCK             (HMFS_BLOCK_SIZE / sizeof(NatEntry))
#define HMFS_HASH_COL_BIT               ((0x1ULL) << HMFS_HASH_COL_BIT_SHIFT)

} // namespace Hmfs
} // namespace OHOS
#endif // HMFS_UTILS_H
